package com.company

import kotlin.math.absoluteValue

fun main() {

    var c = ClassOperate()
    println(c.name)
    c.name = " rose "
    println(c.name)


    var cons = Construce("jack", 20, true)
//    cons.name = "rose"
    println(cons.name)

    val cons2 = Construce2("jack", 20)
    println(cons2.name)

    val stu = Student("rose")


    val tea = Teacher("jack")
//    tea.ready() //
    tea.battle()

    println(tea.config)
}

class ClassOperate {
    //1、field
    var name = "jack"
        get() = field.capitalize()
        set(value) {
            field = value.trim()
        }

    var age = 11
        get() = field.absoluteValue
        private set(value) {
            field = value.absoluteValue
        }

    //2、计算属性:通过一个覆盖的get或set运算符来定义，不需要field了
    val rolledValue
        get() = (1..6).shuffled().first()

    //3、防范竞态条件：如果类属性既可空又可变，必须保证非空
    var words: String? = "hello"
    fun saySomething() {
        words?.also { println("Hello ${it.toUpperCase()}") }
    }

}

//4、初始化
//主构造函数    临时变量（包括仅引用一次的参数） 通常以下划线开头的名字命名
class Construce(_name: String, _age: Int, _isNormal: Boolean) {

    var name = _name
        get() = field.capitalize()
        private set(value) {
            value.trim()
        }
    var age = _age
    var isNormal = _isNormal
}

//在主构造函数里定义属性  age可设置默认值
class Construce2(_name: String, var age: Int = 20, var isNormal: Boolean) {

    var name = _name
        get() = field.capitalize()
        private set(value) {
            value.trim()
        }

    //次构造函数
    constructor(_name: String) : this(_name, age = 11, isNormal = false)

    //次构造函数里定义初始化代码逻辑
    constructor(_name: String, _age: Int) : this(_name, _age, isNormal = false) {
        this.name = _name.toUpperCase()
    }


    //5、初始化块：在构造类实例时执行      可设置变量或值，执行有效性检查
    init {
        require(age > 0) { "age must be positive" }
        require(name.isNotBlank()) { "const must be have a name." }
    }

}

//6、初始化顺序  通过查看 show kotlin bytecode可知
//主构造函数声明的属性(age)--类级别的属性赋值(name score hobby)--init初始化块里的属性赋值和函数调用(subject)--次构造函数里的属性赋值和函数调用(score)
class Student(_name: String, val age: Int) {
    var name = _name
    var score = 10
    private val hobby = "music"
    val subject: String

    init {
        println("init student")
        subject = "math"
    }

    constructor(_name: String) : this(_name, 10) {
        score = 20
    }
}

//7、延迟初始化   lateinit：在用它之前负责初始化  只要无法确认lateinit变量是否是否完成初始化，可执行isInitialized
class Teacher(_name: String) {
    lateinit var equipment: String
    fun ready() {
        equipment = "sharp knife"
    }

    fun battle() {
//        println(equipment)
        if (::equipment.isInitialized) println(equipment)
    }


    //8、惰性初始化(by lazy)  也可以推迟初始化  可以暂时不初始化某个变量直到首次使用它再进行初始化
    var name = _name
    val config by lazy { loadConfig() }
    private fun loadConfig(): String {
        println("loading...")
        return "xxx"
    }


    //预防初始化陷阱 保证顺序

}



